#include "vcom.h"

#ifdef DEBUG
#include "led.h"
#endif

/* you need edit this code, port to your project */
#ifdef __SDCC
#define RX P3_2
#define TX P3_3
#else // Keil C51
sbit RX = P3^2;
sbit TX = P3^3;
#endif

// Tx
volatile uint vcom_tx_SBUF;
volatile bit vcom_TI = 0;

// Rx
volatile uchar vcom_rx_SBUF;
volatile bit vcom_REN = 0;
volatile bit vcom_RI = 0;

volatile bit vcom_ES = 0;
// 76800
void vcom_init(ulong baudrate)
{
    TMOD &= 0xf0;
    TMOD |= 0x02; // set T0 as 8 bit autoreload timer
    TL0 = 256 - fosc / 12 / baudrate;
    TH0 = 256 - fosc / 12 / baudrate;
    /* enable T0 interrupt */
    EA = 1;
    ET0 = 1; // enable T0 interrupt
    TX = 1; // pull Tx to 1
}

void vcom_enable_recv(ulong baudrate)
{
    TMOD &= 0x0f;
    TMOD |= 0x20;  // set T1 as 8 bit autoreload timer
    TL1 = 256 - fosc / 12 / baudrate;
    TH1 = 256 - fosc / 12 / baudrate;

	EA = 1;
    ET1 = 1; // enable T1 interrupt
	IT0 = 1; // fall edge interrupt
	EX0 = 1; // enable external 0 interrupt
    RX = 1; // pull Rx to 1
}

void vcom_enable_it(void)
{
    vcom_ES = 1;
}

void vcom_send(uchar * str)
{
    while(*str != '\0')
    {
	    vcom_tx_SBUF = *str;
        TR0 = 1; //start T0
        vcom_TI = 0;
        while(!vcom_TI);
        TR0 = 0; // stop T0
       str ++;
    }
}

void vcom_recv(uchar * str, volatile uchar count)
{
    vcom_REN = 1;
    while(count)
    {
        while(!vcom_RI);
        *str = vcom_rx_SBUF;
        count --;
        str ++;
        vcom_RI = 0;
    }
    vcom_REN = 0;
    *str = '\0';
}

inline void vcom_rx_user_handler(void)
{
    vcom_send("Yes\r\n");
}

void vcom_tx_it(void ) interrupt 1
{
    static uchar tx_bit_index = 0;

    if(vcom_TI)
        return;

    if(tx_bit_index ==0)
    {
        vcom_tx_SBUF <<= 1;
        vcom_tx_SBUF |= 0x200;
    }

    else if(tx_bit_index == 10)
    {
        vcom_TI = 1;
        tx_bit_index = 0;
        return;
    }

    TX = vcom_tx_SBUF & 0x01;
    vcom_tx_SBUF >>= 1;

    tx_bit_index ++;
}

// external interrupt 0
void vcom_rx_trigger_it(void) interrupt 0
{
    if(!vcom_REN | vcom_RI) return;

    vcom_rx_SBUF = 0x00;

    EX0 = 0; // disbale falling edge trigger
    TR1 = 1; // enable T1 interrupt
}

void vcom_rx_it(void) interrupt 3
{
    static uchar rx_bit_index = 0;

    if(rx_bit_index == 8)
    {
        if(RX == 1)
        {
            vcom_RI = 1;
            if(vcom_ES)
            {
                // vcom_rx_user_handler();
            }
        }
        rx_bit_index = 0;
        EX0 = 1;
        TR1 = 0;
        return;
    }
    vcom_rx_SBUF |= RX << rx_bit_index ;
    rx_bit_index ++;
}
